#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : lei.wang
from typing import Annotated, Dict, Any
from fastapi import Depends
from fastcrud import FastCRUD
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import Users, ChatMessages, UserScore
from app.core.db.database import async_get_db
from app.schemes.user import UserCreate
from app.schemes.score import UserScoreCreate, UserScoreUpdate
from app.core.pkg.log import logger
from datetime import datetime
from enum import Enum
from sqlalchemy import insert


user_service = FastCRUD(Users)
chat_messages_service = FastCRUD(ChatMessages)
user_score_service = FastCRUD(UserScore)


# 兼容不同版本的Pydantic
def model_to_dict(model) -> Dict[str, Any]:
    """将Pydantic模型转换为字典，兼容v1和v2版本"""
    if model is None:
        return {}
    if isinstance(model, dict):
        return model
    if hasattr(model, "model_dump"):
        # Pydantic v2
        return model.model_dump()
    elif hasattr(model, "dict"):
        # Pydantic v1
        return model.dict()
    else:
        # 回退方案：使用__dict__但要移除私有属性
        return {k: v for k, v in model.__dict__.items() if not k.startswith('_')}


# 确保对象是安全的纯字典形式，不包含复杂对象
def ensure_safe_dict(data: Dict[str, Any]) -> Dict[str, Any]:
    """将字典中的复杂对象转换为简单类型，确保可以安全序列化"""
    result = {}
    for key, value in data.items():
        # 处理枚举类型
        if isinstance(value, Enum):
            result[key] = str(value)
        # 处理日期时间类型
        elif isinstance(value, datetime):
            result[key] = value
        # 处理其他复杂对象
        elif hasattr(value, '__dict__'):
            result[key] = str(value)
        # 对于可能为NULL但列上有NOT NULL约束的字段，设置默认值
        elif value is None and key in ('total_score', 'used_score'):
            # 跳过NULL值以保留数据库中的原值
            continue
        # 基本类型直接保留
        else:
            result[key] = value
    return result


class UserService:
    """
    用户服务类
    """

    def __init__(self, db: Annotated[AsyncSession, Depends(async_get_db)]):
        self.user_service = user_service
        self.db = db
    
    async def check_user_exist(self, username: str) -> bool:
        return await self.user_service.exists(db=self.db, username=username)

    async def create_user(self, user: UserCreate) -> Users:
        try:
            # 将Pydantic模型转换为字典，并确保安全
            user_data = model_to_dict(user)
            safe_user_data = ensure_safe_dict(user_data)
            
            logger.debug(f"User data before create: {safe_user_data}")
            user = await self.user_service.create(db=self.db, object=UserCreate(**safe_user_data))
            return user
        except Exception as e:
            logger.error(f"Error creating user: {str(e)}")
            raise
    
    async def get_user_by_username(self, username: str) -> Users:
        return await self.user_service.get(db=self.db, username=username)

    async def get_user_by_payload_id(self, payload_id: str) -> Users:
        """根据payload_id获取用户信息"""
        return await self.user_service.get(db=self.db, payload_id=payload_id)
    
    async def update_user_birthday(self, payload_id: str, birthday: str) -> Users:
        """更新用户生日信息"""
        try:
            # 检查用户是否存在
            user = await self.get_user_by_payload_id(payload_id)
            if not user:
                logger.warning(f"User not found for payload_id: {payload_id}")
                return None
                
            # 准备更新数据
            now = datetime.now()
            update_data = {
                "birthday": birthday,
            }
            from app.schemes.user import UserUpdateBirthday
            
            # 确保数据安全
            safe_update_data = ensure_safe_dict(update_data)
            
            logger.info(f"Updating birthday for user: {payload_id}, new birthday: {birthday}")
            logger.debug(f"User data before update: {safe_update_data}")
            
            # 执行更新操作
            try:
                updated_user = await self.user_service.update(db=self.db, payload_id=payload_id, object=UserUpdateBirthday(**safe_update_data))
                return updated_user
            except Exception as db_err:
                logger.error(f"Database error in update_user_birthday: {str(db_err)}")
                raise Exception(f"数据库更新用户生日错误: {str(db_err)}")
        except Exception as e:
            logger.error(f"Error updating user birthday: {str(e)}")
            raise

    async def update_user_gender(self, payload_id: str, gender: str) -> Users:
        """更新用户性别信息"""
        try:
            # 检查用户是否存在
            user = await self.get_user_by_payload_id(payload_id)
            if not user:
                logger.warning(f"User not found for payload_id: {payload_id}")
                return None
                
            # 准备更新数据
            now = datetime.now()
            update_data = {
                "gender": gender,
            }
            from app.schemes.user import UserUpdateGender
            
            # 确保数据安全
            safe_update_data = ensure_safe_dict(update_data)
            
            logger.info(f"Updating gender for user: {payload_id}, new gender: {gender}")
            logger.debug(f"User data before update: {safe_update_data}")
            
            # 执行更新操作
            try:
                updated_user = await self.user_service.update(db=self.db, payload_id=payload_id, object=UserUpdateGender(**safe_update_data))
                return updated_user
            except Exception as db_err:
                logger.error(f"Database error in update_user_gender: {str(db_err)}")
                raise Exception(f"数据库更新用户性别错误: {str(db_err)}")
        except Exception as e:
            logger.error(f"Error updating user gender: {str(e)}")
            raise


class UserScoreService:
    """
    用户积分服务类
    """

    def __init__(self, db: Annotated[AsyncSession, Depends(async_get_db)]):
        self.user_score_service = user_score_service
        self.db = db
    
    async def create_user_score(self, user_score: UserScoreCreate | dict) -> UserScore:
        try:
            # 检查user_score是否已经是字典
            if isinstance(user_score, dict):
                score_data = user_score
            else:
                # 如果是Pydantic模型，转换为字典
                score_data = model_to_dict(user_score)
                
            logger.info(f"Creating user score for user: {score_data.get('payload_id')}")
            
            # 准备插入数据
            now = datetime.now()
            insert_data = {
                "payload_id": score_data.get("payload_id"),
                "total_score": score_data.get("total_score", 0),
                "used_score": score_data.get("used_score", 0),
                "created_at": now,
                "is_deleted": False
            }
            
            logger.debug(f"User score data before create: {insert_data}")
            
            try:
                # 使用原始SQL插入语句
                stmt = insert(UserScore).values(**insert_data)
                result = await self.db.execute(stmt)
                await self.db.commit()
                
                # 获取创建后的积分记录
                user_score_result = await self.user_score_service.get(self.db, payload_id=score_data.get("payload_id"))
                logger.info(f"User score created successfully for user: {score_data.get('payload_id')}")
                
                return user_score_result
            except Exception as db_err:
                await self.db.rollback()
                logger.error(f"Database error in create_user_score: {str(db_err)}")
                raise Exception(f"数据库创建用户积分错误: {str(db_err)}")
        except Exception as e:
            logger.error(f"Error creating user score: {str(e)}")
            raise

    async def get_user_score(self, payload_id: str) -> UserScore:
        """ 获取用户积分 """
        return await self.user_score_service.get(db=self.db, payload_id=payload_id)

    async def update_user_score(self, user_score: UserScoreUpdate) -> UserScore:
        """ 更新用户积分 """
        try:
            score_user = await self.get_user_score(user_score.payload_id)
            if not score_user:
                logger.warning(f"User score not found for user: {user_score.payload_id}")
                return None
                
            # 转换为字典并更新used_score
            score_data = model_to_dict(user_score)
            score_data["used_score"] += score_user.get('used_score', 0)
            
            # 保留原始total_score，确保不会被设置为None
            if score_data.get("total_score") is None:
                score_data["total_score"] = score_user.get('total_score', 0)
            
            # 确保是安全的字典格式
            safe_score_data = ensure_safe_dict(score_data)
            
            logger.info(f"Updating score for user: {user_score.payload_id}, used_score: {safe_score_data['used_score']}, total_score: {safe_score_data['total_score']}")
            logger.debug(f"User score data before update: {safe_score_data}")
            
            try:
                return await self.user_score_service.update(db=self.db, payload_id=user_score.payload_id, object=safe_score_data)
            except Exception as db_err:
                logger.error(f"Database error in update_user_score: {str(db_err)}")
                raise Exception(f"数据库更新用户积分错误: {str(db_err)}")
        except Exception as e:
            logger.error(f"Error updating user score: {str(e)}")
            raise
    
    async def add_sign_score(self, payload_id: str) -> int:
        """ 用户签到增加积分 """
        try:
            # 签到积分值
            sign_score = 5
            
            # 获取用户当前积分
            user_score = await self.get_user_score(payload_id)
            if not user_score:
                logger.warning(f"User score not found for user: {payload_id}")
                return 0
            
            # 创建更新对象
            score_update = UserScoreUpdate(
                payload_id=payload_id,
                total_score=user_score.get("total_score", 0) + sign_score,
                used_score=0
            )
            
            # 更新用户积分
            await self.user_score_service.update(
                db=self.db, 
                payload_id=payload_id, 
                object={"total_score": score_update.total_score}
            )
            
            logger.info(f"Added {sign_score} sign-in points for user: {payload_id}")
            return sign_score
            
        except Exception as e:
            logger.error(f"Error adding sign score: {str(e)}")
            await self.db.rollback()
            raise Exception(f"签到增加积分失败: {str(e)}")
